package com.winner.data.service.impl;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.winner.data.dao.UserMapper;
import com.winner.data.entity.User;
import com.winner.data.entity.request.UserImport;
import com.winner.data.entity.request.UserParam;
import com.winner.data.entity.vo.UserVo;
import com.winner.data.service.UserService;
import com.winner.data.util.MybatisBatchUtil;

import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 用户管理服务实现类
 *
 * @author wangxinle5
 * @since 2021-07-19
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    MybatisBatchUtil mybatisBatchUtil;

    @Resource
    UserMapper userMapper;

    @Override
    public List<User> match() {
        return userMapper.match();
    }

    @Async
    @Override
    public void saveImportData(List<UserImport> list) {
        log.info("线程" + Thread.currentThread().getName() + " 执行异步任务：");
        // 转为数据库对象 批量保存
        List<User> userList = list.stream().map(a -> {
            User user = new User();
            BeanUtils.copyProperties(a, user);
            return user;
        }).collect(Collectors.toList());
        mybatisBatchUtil.batchUpdateOrInsert(userList, UserMapper.class, (item, mapper) -> mapper.insertOne(item));
    }

    @Override
    public List<User> getByList(List<User> list) {
        return userMapper.getByList(list);
    }

    /**
     * 分页处理 pageNum 推荐此, 不推荐下面的offset分页处理, 比较麻烦(还得写sql limit)
     */
    @Override
    public void processPageByPageNum() {
        log.info("processPageByPageNum method start");
        int pageNum = 1;
        while (true) {
            Page<User> iPage = new Page<>(pageNum, MybatisBatchUtil.BATCH_SIZE);
            // 使用 select 方法的投影功能来指定返回的字段
            IPage<User> page = lambdaQuery().eq(User::getName, "张三").select(User::getId, User::getName).page(iPage);
            List<User> userList = page.getRecords();
            if (CollUtil.isNotEmpty((userList))) {
                // 处理业务 我们看{} 条,就可以知道是不是最后一次
                log.info("processPageByPageNum process {} 条", userList.size());
            }
            if (userList.size() < MybatisBatchUtil.BATCH_SIZE) {
                // 说明是最后一次查询, 调出循环
                break;
            }
            pageNum = pageNum + 1;
        }
        log.info("processPageByPageNum method end");
    }

    /**
     * 分页处理 offset
     */
    @Override
    public void processPageByOffset() {
        log.info("processPageByOffset method start");
        // 记录行的偏移量 = (pageNum - 1) * pageSize, 初始记录行的偏移量是 0 (而不是1)
        int offset = 0;
        int pageSize = MybatisBatchUtil.BATCH_SIZE;
        while (true) {
            List<User> userList = userMapper.getByPage(offset, pageSize);
            if (CollUtil.isNotEmpty((userList))) {
                // 处理业务 我们看{} 条,就可以知道是不是最后一次
                log.info("processPageByOffset process {} 条", userList.size());
            }
            if (userList.size() < MybatisBatchUtil.BATCH_SIZE) {
                // 说明是最后一次查询, 调出循环
                break;
            }
            offset = offset + MybatisBatchUtil.BATCH_SIZE;
        }
        log.info("processPageByOffset method end");
    }

    @Override
    public Page<UserVo> getByPage(Integer pageNum, Integer pageSize) {
        Page<UserVo> iPage = new Page<>(pageNum, pageSize);
        UserParam userParam = new UserParam();
//        userParam.setName("张三");
        // return iPage; // 返回没有数据的情况
        // {"code":0,"message":"成功","data":{"records":[],"total":0,"size":10,"current":1,"orders":[],"hitCount":false,"searchCount":true,"pages":0}}
        return userMapper.selectByPage(iPage, userParam);
    }

    @Async
    @Override
    public void executeAsyncTask(int i, CountDownLatch countDownLatch) throws InterruptedException {
        Thread.sleep(5000);
        log.info("线程" + Thread.currentThread().getName() + " 执行异步任务：" + i);
        countDownLatch.countDown(); // 触发事件
    }

    @Async
    @Override
    public CompletableFuture<String> pullDataA() throws InterruptedException {
        log.info("A : " + Thread.currentThread().getName() + "  " + UUID.randomUUID());
        Thread.sleep(2000L);
        log.info("A 数据拉取成功");
        return CompletableFuture.completedFuture("A");
    }

    @Async
    @Override
    public CompletableFuture<String> pullDataB() throws InterruptedException {
        log.info("B : " + Thread.currentThread().getName() + "  " + UUID.randomUUID());
        Thread.sleep(2000L);
        log.info("B 数据拉取成功");
        return CompletableFuture.completedFuture("B");
    }

    @Async
    @Override
    public CompletableFuture<String> pullDataC() throws InterruptedException {
        log.info("C : " + Thread.currentThread().getName() + "  " + UUID.randomUUID());
        Thread.sleep(2000L);
        log.info("C 数据拉取成功");
        return CompletableFuture.completedFuture("C");
    }

}
